/**
 * 统一工具函数库
 * @description 整合所有工具函数，提供统一的导入入口
 * @author AI Assistant
 * @date 2025-08-18
 */

// ================================
// 图片相关工具函数
// ================================

/**
 * 获取图片地址
 * @param url 图片路径
 * @returns 完整的图片URL
 */
export const getImageUrl = (url?: string): string => {
    if (!url) return ''

    // 如果已经是完整URL，直接返回
    if (url.startsWith('http') || url.startsWith('data:')) {
        return url
    }

    // 获取基础URL
    const baseUrl = import.meta.env.VITE_APP_BASE_URL || ''
    if (!baseUrl) {
        console.warn('VITE_APP_BASE_URL 未配置，使用相对路径')
        return url
    }

    // 处理斜杠拼接问题
    const cleanBaseUrl = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl
    const cleanUrl = url.startsWith('/') ? url : '/' + url

    return cleanBaseUrl + cleanUrl
}

/**
 * 获取用户头像地址
 * @param url 头像路径
 * @returns 头像URL，如果没有则返回默认头像
 */
export const getHeaderImage = (url?: string): string => {
    return url ? getImageUrl(url) : '/static/images/default-avatar.png'
}

/**
 * 图片预加载
 * @param url 图片URL
 * @returns Promise<boolean> 是否加载成功
 */
export const preloadImage = async (url: string): Promise<boolean> => {
    if (!url) return false

    try {
        await new Promise((resolve, reject) => {
            // #ifdef H5
            const img = new Image()
            img.onload = resolve
            img.onerror = reject
            img.src = url
            // #endif
            // #ifdef MP-WEIXIN || APP-PLUS
            uni.getImageInfo({
                src: url,
                success: resolve,
                fail: reject
            })
            // #endif
        })
        return true
    } catch (error) {
        console.error('Failed to preload image:', url, error)
        return false
    }
}

/**
 * 批量预加载图片
 * @param urls 图片URL数组
 * @returns Promise<boolean[]> 每个图片的加载结果
 */
export const preloadImages = async (urls: string[]): Promise<boolean[]> => {
    return Promise.all(urls.map((url) => preloadImage(url)))
}

// ================================
// 性能优化工具函数
// ================================

/**
 * 防抖函数
 * @param func 要防抖的函数
 * @param delay 延迟时间(ms)
 * @returns 防抖后的函数
 */
export function debounce<T extends (...args: any[]) => any>(func: T, delay: number): (...args: Parameters<T>) => void {
    let timeoutId: number
    return (...args: Parameters<T>) => {
        clearTimeout(timeoutId)
        timeoutId = setTimeout(() => func(...args), delay)
    }
}

/**
 * 节流函数
 * @param func 要节流的函数
 * @param delay 延迟时间(ms)
 * @returns 节流后的函数
 */
export function throttle<T extends (...args: any[]) => any>(func: T, delay: number): (...args: Parameters<T>) => void {
    let lastCall = 0
    return (...args: Parameters<T>) => {
        const now = Date.now()
        if (now - lastCall >= delay) {
            lastCall = now
            func(...args)
        }
    }
}

/**
 * 延迟执行
 * @param ms 延迟时间(ms)
 * @returns Promise<void>
 */
export const delay = (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms))

/**
 * 空闲时执行
 * @param callback 回调函数
 */
export const runOnIdle = (callback: () => void): void => {
    // #ifdef H5
    if ('requestIdleCallback' in window) {
        requestIdleCallback(callback)
    } else {
        setTimeout(callback, 0)
    }
    // #endif
    // #ifdef MP-WEIXIN || APP-PLUS
    setTimeout(callback, 0)
    // #endif
}

/**
 * 批量执行任务
 * @param tasks 任务数组
 * @param batchSize 批次大小
 * @returns Promise<T[]> 执行结果
 */
export async function batchExecute<T>(tasks: (() => Promise<T>)[], batchSize = 3): Promise<T[]> {
    const results: T[] = []
    for (let i = 0; i < tasks.length; i += batchSize) {
        const batch = tasks.slice(i, i + batchSize)
        const batchResults = await Promise.all(batch.map((task) => task()))
        results.push(...batchResults)
    }
    return results
}

/**
 * 创建并发控制器
 * @param limit 并发限制数量
 * @returns 并发控制器
 */
export const createConcurrencyController = (limit = 3) => {
    let running = 0
    const queue: Array<() => void> = []

    const execute = async <T>(task: () => Promise<T>): Promise<T> => {
        return new Promise((resolve, reject) => {
            const run = async () => {
                running++
                try {
                    const result = await task()
                    resolve(result)
                } catch (error) {
                    reject(error)
                } finally {
                    running--
                    if (queue.length > 0 && running < limit) {
                        const next = queue.shift()
                        if (next) next()
                    }
                }
            }

            if (running < limit) {
                run()
            } else {
                queue.push(run)
            }
        })
    }

    return { execute }
}

// ================================
// 验证相关工具函数
// ================================

/**
 * 验证手机号
 * @param phone 手机号
 * @returns boolean 是否有效
 */
export const validatePhone = (phone: string): boolean => {
    return /^1[3-9]\d{9}$/.test(phone)
}

/**
 * 验证密码
 * @param password 密码
 * @returns boolean 是否有效
 */
export const validatePassword = (password: string): boolean => {
    if (password.trim() === '') return false
    return /^(?=.*\d)(?=.*[a-zA-Z])(?=.*[^a-zA-Z0-9]).{8,16}$/.test(password)
}

/**
 * 验证邮箱
 * @param email 邮箱
 * @returns boolean 是否有效
 */
export const validateEmail = (email: string): boolean => {
    return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)
}

// ================================
// 日期时间工具函数
// ================================

/**
 * 格式化日期
 * @param date 日期
 * @param format 格式化字符串
 * @returns 格式化后的日期字符串
 */
export const formatDate = (date: Date | string, format = 'YYYY-MM-DD HH:mm:ss'): string => {
    const d = new Date(date)
    if (isNaN(d.getTime())) return ''

    const year = d.getFullYear()
    const month = String(d.getMonth() + 1).padStart(2, '0')
    const day = String(d.getDate()).padStart(2, '0')
    const hours = String(d.getHours()).padStart(2, '0')
    const minutes = String(d.getMinutes()).padStart(2, '0')
    const seconds = String(d.getSeconds()).padStart(2, '0')

    return format
        .replace('YYYY', String(year))
        .replace('MM', month)
        .replace('DD', day)
        .replace('HH', hours)
        .replace('mm', minutes)
        .replace('ss', seconds)
}

/**
 * 获取相对时间
 * @param date 日期
 * @returns 相对时间字符串
 */
export const getRelativeTime = (date: Date | string): string => {
    const now = new Date()
    const target = new Date(date)
    const diff = now.getTime() - target.getTime()

    const minute = 60 * 1000
    const hour = 60 * minute
    const day = 24 * hour

    if (diff < minute) return '刚刚'
    if (diff < hour) return `${Math.floor(diff / minute)}分钟前`
    if (diff < day) return `${Math.floor(diff / hour)}小时前`
    if (diff < 7 * day) return `${Math.floor(diff / day)}天前`

    return formatDate(target, 'MM-DD')
}

// ================================
// 数据处理工具函数
// ================================

/**
 * 深拷贝
 * @param obj 要拷贝的对象
 * @returns 拷贝后的对象
 */
export const deepClone = <T>(obj: T): T => {
    if (obj === null || typeof obj !== 'object') return obj
    if (obj instanceof Date) return new Date(obj.getTime()) as unknown as T
    if (obj instanceof Array) return obj.map((item) => deepClone(item)) as unknown as T
    if (typeof obj === 'object') {
        const clonedObj = {} as T
        for (const key in obj) {
            if (obj.hasOwnProperty(key)) {
                clonedObj[key] = deepClone(obj[key])
            }
        }
        return clonedObj
    }
    return obj
}

/**
 * 对象转URL参数
 * @param obj 对象
 * @returns URL参数字符串
 */
export const objectToQuery = (obj: Record<string, any>): string => {
    return Object.keys(obj)
        .filter((key) => obj[key] !== undefined && obj[key] !== null && obj[key] !== '')
        .map((key) => `${encodeURIComponent(key)}=${encodeURIComponent(obj[key])}`)
        .join('&')
}

/**
 * URL参数转对象
 * @param query URL参数字符串
 * @returns 对象
 */
export const queryToObject = (query: string): Record<string, string> => {
    const result: Record<string, string> = {}
    if (!query) return result

    query
        .replace(/^\?/, '')
        .split('&')
        .forEach((param) => {
            const [key, value] = param.split('=')
            if (key) {
                result[decodeURIComponent(key)] = decodeURIComponent(value || '')
            }
        })

    return result
}

// ================================
// 存储相关工具函数
// ================================

/**
 * 简单的存储适配器
 */
export class SimpleStorage {
    /**
     * 设置存储
     * @param key 键
     * @param value 值
     */
    static set(key: string, value: any): void {
        try {
            const stringValue = JSON.stringify(value)
            // #ifdef H5
            localStorage.setItem(key, stringValue)
            // #endif
            // #ifdef MP-WEIXIN || APP-PLUS
            uni.setStorageSync(key, stringValue)
            // #endif
        } catch (error) {
            console.error('存储失败:', error)
        }
    }

    /**
     * 获取存储
     * @param key 键
     * @returns 值
     */
    static get(key: string): any {
        try {
            let value = null
            // #ifdef H5
            value = localStorage.getItem(key)
            // #endif
            // #ifdef MP-WEIXIN || APP-PLUS
            value = uni.getStorageSync(key)
            // #endif

            return value ? JSON.parse(value) : null
        } catch (error) {
            console.error('读取存储失败:', error)
            return null
        }
    }

    /**
     * 删除存储
     * @param key 键
     */
    static remove(key: string): void {
        try {
            // #ifdef H5
            localStorage.removeItem(key)
            // #endif
            // #ifdef MP-WEIXIN || APP-PLUS
            uni.removeStorageSync(key)
            // #endif
        } catch (error) {
            console.error('删除存储失败:', error)
        }
    }

    /**
     * 清空存储
     */
    static clear(): void {
        try {
            // #ifdef H5
            localStorage.clear()
            // #endif
            // #ifdef MP-WEIXIN || APP-PLUS
            uni.clearStorageSync()
            // #endif
        } catch (error) {
            console.error('清空存储失败:', error)
        }
    }
}

// ================================
// 内存缓存管理
// ================================

/**
 * 简单的内存缓存
 */
const cache = new Map<string, { data: any; expiry: number }>()

export const memoryManager = {
    /**
     * 设置缓存
     * @param key 键
     * @param data 数据
     * @param ttl 过期时间(ms)
     */
    set(key: string, data: any, ttl = 3600000): void {
        cache.set(key, {
            data,
            expiry: Date.now() + ttl
        })
    },

    /**
     * 获取缓存
     * @param key 键
     * @returns 数据
     */
    get(key: string): any {
        const item = cache.get(key)
        if (!item) return null

        if (Date.now() > item.expiry) {
            cache.delete(key)
            return null
        }

        return item.data
    },

    /**
     * 删除缓存
     * @param key 键
     */
    delete(key: string): void {
        cache.delete(key)
    },

    /**
     * 清空缓存
     */
    clear(): void {
        cache.clear()
    },

    /**
     * 获取缓存大小
     * @returns 缓存项数量
     */
    size(): number {
        return cache.size
    }
}

// ================================
// 性能监控工具
// ================================

/**
 * 简单的性能监控
 */
const performanceMarks = new Map<string, number>()

export const performanceMonitor = {
    /**
     * 标记时间点
     * @param name 标记名称
     */
    mark(name: string): void {
        performanceMarks.set(name, Date.now())
    },

    /**
     * 测量时间差
     * @param startMark 开始标记
     * @param endMark 结束标记
     * @returns 时间差(ms)
     */
    measure(startMark: string, endMark?: string): number {
        const startTime = performanceMarks.get(startMark)
        const endTime = endMark ? performanceMarks.get(endMark) : Date.now()

        if (!startTime || !endTime) return 0
        return endTime - startTime
    },

    /**
     * 清空标记
     */
    clear(): void {
        performanceMarks.clear()
    }
}

// ================================
// 页面跳转工具函数
// ================================

/**
 * 页面跳转
 * @param options 跳转选项
 */
export const goToPage = (options: {
    url: string
    mode?: 'navigateTo' | 'redirectTo' | 'reLaunch' | 'switchTab' | 'navigateBack'
    params?: Record<string, any>
}): void => {
    const { url, mode = 'navigateTo', params } = options

    let finalUrl = url
    if (params && Object.keys(params).length > 0) {
        const query = objectToQuery(params)
        finalUrl = `${url}${url.includes('?') ? '&' : '?'}${query}`
    }

    switch (mode) {
        case 'navigateTo':
            uni.navigateTo({ url: finalUrl })
            break
        case 'redirectTo':
            uni.redirectTo({ url: finalUrl })
            break
        case 'reLaunch':
            uni.reLaunch({ url: finalUrl })
            break
        case 'switchTab':
            uni.switchTab({ url: finalUrl })
            break
        case 'navigateBack':
            uni.navigateBack()
            break
        default:
            uni.navigateTo({ url: finalUrl })
    }
}

// ================================
// 文件处理工具函数
// ================================

/**
 * 获取文件扩展名
 * @param filename 文件名
 * @returns 扩展名
 */
export const getFileExtension = (filename: string): string => {
    return filename.slice(((filename.lastIndexOf('.') - 1) >>> 0) + 2)
}

/**
 * 格式化文件大小
 * @param bytes 字节数
 * @returns 格式化后的大小
 */
export const formatFileSize = (bytes: number): string => {
    if (bytes === 0) return '0 B'

    const k = 1024
    const sizes = ['B', 'KB', 'MB', 'GB', 'TB']
    const i = Math.floor(Math.log(bytes) / Math.log(k))

    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
}

// ================================
// 数字处理工具函数
// ================================

/**
 * 格式化数字
 * @param num 数字
 * @param precision 精度
 * @returns 格式化后的数字字符串
 */
export const formatNumber = (num: number, precision = 2): string => {
    if (num >= 1e9) return (num / 1e9).toFixed(precision) + 'B'
    if (num >= 1e6) return (num / 1e6).toFixed(precision) + 'M'
    if (num >= 1e3) return (num / 1e3).toFixed(precision) + 'K'
    return num.toString()
}

/**
 * 生成随机数
 * @param min 最小值
 * @param max 最大值
 * @returns 随机数
 */
export const randomNumber = (min: number, max: number): number => {
    return Math.floor(Math.random() * (max - min + 1)) + min
}

/**
 * 生成UUID
 * @returns UUID字符串
 */
export const generateUUID = (): string => {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
        const r = (Math.random() * 16) | 0
        const v = c === 'x' ? r : (r & 0x3) | 0x8
        return v.toString(16)
    })
}

// ================================
// 导出文件工具函数
// ================================

/**
 * 下载文件
 * @param content 文件内容
 * @param fileName 文件名
 * @param mimeType MIME类型
 */
export const downloadFile = (content: string, fileName: string, mimeType: string): void => {
    // #ifdef H5
    const blob = new Blob([content], { type: mimeType })
    const url = URL.createObjectURL(blob)

    const a = document.createElement('a')
    a.href = url
    a.download = fileName
    document.body.appendChild(a)
    a.click()
    document.body.removeChild(a)
    URL.revokeObjectURL(url)
    // #endif

    // #ifdef MP-WEIXIN || APP-PLUS
    console.warn('小程序和App环境不支持直接下载文件')
    // #endif
}

/**
 * 导出JSON文件
 * @param data 数据
 * @param fileName 文件名
 */
export const exportJson = (data: any, fileName = 'data.json'): void => {
    const content = JSON.stringify(data, null, 2)
    downloadFile(content, fileName, 'application/json')
}

/**
 * 导出CSV文件
 * @param data 数据数组
 * @param fileName 文件名
 */
export const exportCsv = (data: any[], fileName = 'data.csv'): void => {
    if (!data.length) return

    const headers = Object.keys(data[0]).join(',')
    const rows = data.map((item) => Object.values(item).join(','))
    const content = [headers, ...rows].join('\n')
    downloadFile(content, fileName, 'text/csv')
}

// ================================
// 初始化函数
// ================================

/**
 * 检查API兼容性
 * @returns 兼容性检查结果
 */
export const checkAPICompatibility = () => {
    // #ifdef H5
    return {
        requestAnimationFrame: typeof requestAnimationFrame !== 'undefined',
        performance: typeof performance !== 'undefined',
        intersectionObserver: typeof IntersectionObserver !== 'undefined',
        localStorage: typeof localStorage !== 'undefined'
    }
    // #endif

    // #ifdef MP-WEIXIN || APP-PLUS
    return {
        requestAnimationFrame: false,
        performance: false,
        intersectionObserver: false,
        localStorage: false
    }
    // #endif
}

/**
 * 安全的requestAnimationFrame
 * @param callback 回调函数
 * @returns 定时器ID
 */
export const safeRequestAnimationFrame = (callback: () => void): number => {
    // #ifdef H5
    if (typeof requestAnimationFrame !== 'undefined') {
        return requestAnimationFrame(callback)
    }
    // #endif

    // 降级到setTimeout
    return setTimeout(callback, 16) // 约60fps
}

/**
 * 安全的cancelAnimationFrame
 * @param id 定时器ID
 */
export const safeCancelAnimationFrame = (id: number): void => {
    // #ifdef H5
    if (typeof cancelAnimationFrame !== 'undefined') {
        cancelAnimationFrame(id)
        return
    }
    // #endif

    // 降级到clearTimeout
    clearTimeout(id)
}

/**
 * 初始化性能优化 + 轻量监控
 */
export function initPerformanceOptimization(): void {
    if (import.meta.env.MODE === 'development') {
        console.log('Performance optimization initialized')
        console.log('API Compatibility:', checkAPICompatibility())
    }

    // 监听内存警告
    // #ifdef MP-WEIXIN
    try {
        uni.onMemoryWarning(() => {
            console.warn('Memory warning detected')
            // 清理缓存
            memoryManager.clear()
        })
    } catch (e) {
        // 忽略错误
    }
    // #endif

    // 轻量性能监控（FPS、首屏耗时）
    // #ifdef H5
    try {
        const perf = window.performance
        const nav = perf.getEntriesByType?.('navigation')?.[0] as PerformanceNavigationTiming
        if (nav) {
            const loadTime = Math.round(nav.loadEventEnd - nav.startTime)
            console.log('[Monitor] loadTime(ms):', loadTime)
        }

        // FPS 采样
        let last = perf.now()
        let frames = 0
        const sample = () => {
            frames++
            const now = perf.now()
            if (now - last >= 1000) {
                const fps = frames
                frames = 0
                last = now
                // 开发环境打印，避免影响线上
                if (import.meta.env.MODE === 'development') {
                    console.log('[Monitor] FPS:', fps)
                }
            }
            safeRequestAnimationFrame(sample)
        }
        safeRequestAnimationFrame(sample)
    } catch (e) {
        // 忽略监控异常
    }
    // #endif
}
